package com.huang.auth.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.huang.auth.constants.*;
import com.huang.auth.converter.AuthRoleInfoVOConverter;
import com.huang.auth.converter.AuthRoleSimpleVOConverter;
import com.huang.auth.dao.AuthResourceDao;
import com.huang.auth.dao.AuthRoleAuthorityDao;
import com.huang.auth.dao.AuthRoleDao;
import com.huang.auth.dao.AuthUserRoleDao;
import com.huang.auth.entity.po.AuthResourcePO;
import com.huang.auth.entity.po.AuthRoleAuthorityPO;
import com.huang.auth.entity.po.AuthRolePO;
import com.huang.auth.entity.po.AuthUserRolePO;
import com.huang.auth.entity.request.AuthRoleAddRequest;
import com.huang.auth.entity.request.AuthRoleEditRequest;
import com.huang.auth.entity.request.AuthRoleQueryRequest;
import com.huang.auth.entity.vo.AuthRoleInfoVO;
import com.huang.auth.entity.vo.AuthRoleSimpleVO;
import com.huang.auth.service.AuthRoleService;
import com.huang.utils.ObjectIdUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 角色(AuthRole)表服务实现类
 *
 * @author HuangShen
 * @since 2021-09-21 17:13:49
 */
@Service("authRoleService")
public class AuthRoleServiceImpl extends ServiceImpl<AuthRoleDao, AuthRolePO> implements AuthRoleService {

    @Resource
    private AuthRoleDao authRoleDao;

    @Resource
    private AuthRoleAuthorityDao authRoleAuthorityDao;
    @Resource
    private AuthRoleSimpleVOConverter authRoleSimpleVOConverter;
    @Resource
    private AuthRoleInfoVOConverter authRoleInfoVOConverter;
    @Resource
    private AuthUserRoleDao authUserRoleDao;
    @Resource
    private AuthResourceDao authResourceDao;

    @Override
    public List<AuthRoleSimpleVO> roleSimpleList() {
        // 查找已经启用的角色
        QueryWrapper<AuthRolePO> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(RoleWrapperConstant.STATUS, true);
        queryWrapper.select(RoleWrapperConstant.NAME, RoleWrapperConstant.CODE, RoleWrapperConstant.ID);
        List<AuthRolePO> authRolePOS = this.authRoleDao.selectList(queryWrapper);
        return authRoleSimpleVOConverter.batchConvert(authRolePOS);
    }

    @Override
    @Transactional
    public boolean creatRole(AuthRoleAddRequest authRoleAddRequest) {

        AuthRolePO authRolePO = new AuthRolePO();
        authRolePO.setId(ObjectIdUtils.getInstance().nextId());
        authRolePO.setCode(authRoleAddRequest.getCode());
        authRolePO.setCreateUser(authRoleAddRequest.getCreateUser());
        authRolePO.setDescribe(authRoleAddRequest.getDescribe());
        authRolePO.setName(authRoleAddRequest.getName());
        authRolePO.setType(authRoleAddRequest.getType());
        authRolePO.setUpdateUser(authRoleAddRequest.getCreateUser());
        // 创建角色 默认未启用
        int roleAdd = authRoleDao.insert(authRolePO);
        if (CollectionUtils.isEmpty(authRoleAddRequest.getMenuIds())) {
            return roleAdd > 0;
        }
        List<AuthRoleAuthorityPO> roleResources = authRoleAddRequest.getResourceIds()
                .stream()
                .map(resourceIds -> {
                    AuthRoleAuthorityPO authRoleAuthorityPO = new AuthRoleAuthorityPO();
                    authRoleAuthorityPO.setId(ObjectIdUtils.getInstance().nextId());
                    authRoleAuthorityPO.setRoleId(authRolePO.getId());
                    authRoleAuthorityPO.setAuthorityId(Long.parseLong(resourceIds));
                    authRoleAuthorityPO.setCreateUser(authRoleAddRequest.getCreateUser());
                    authRoleAuthorityPO.setAuthorityType(AuthConstants.AUTHORITY_TYPE_RESOURCE);
                    authRoleAuthorityPO.setCreateTime(new Date());
                    return authRoleAuthorityPO;
                }).collect(Collectors.toList());
        ArrayList<Long> roleMenuIds = new ArrayList<>();
        List<AuthRoleAuthorityPO> roleMenus = authRoleAddRequest.getMenuIds()
                .stream()
                .map(menuId -> {
                    AuthRoleAuthorityPO authRoleAuthorityPO = new AuthRoleAuthorityPO();
                    authRoleAuthorityPO.setId(ObjectIdUtils.getInstance().nextId());
                    roleMenuIds.add(Long.valueOf(menuId));
                    authRoleAuthorityPO.setRoleId(authRolePO.getId());
                    authRoleAuthorityPO.setAuthorityId(Long.parseLong(menuId));
                    authRoleAuthorityPO.setCreateUser(authRoleAddRequest.getCreateUser());
                    authRoleAuthorityPO.setCreateTime(new Date());
                    authRoleAuthorityPO.setAuthorityType(AuthConstants.AUTHORITY_TYPE_MENU);
                    return authRoleAuthorityPO;
                }).collect(Collectors.toList());
        
        // 查询菜单下的查询资源
        QueryWrapper<AuthResourcePO> queryWrapper = new QueryWrapper<>();
        queryWrapper.in(AuthorityWrapperConstant.MENU_ID,roleMenuIds).eq(AuthorityWrapperConstant.TYPE,AuthConstants.RESOURCE_TYPE_PUBLIC);
        List<AuthRoleAuthorityPO> defaultResource = this.authResourceDao.selectList(queryWrapper).stream().map(resourcePO -> {
            AuthRoleAuthorityPO authRoleAuthorityPO = new AuthRoleAuthorityPO();
            authRoleAuthorityPO.setId(ObjectIdUtils.getInstance().nextId());
            authRoleAuthorityPO.setRoleId(authRolePO.getId());
            authRoleAuthorityPO.setAuthorityId(resourcePO.getId());
            authRoleAuthorityPO.setCreateUser(authRoleAddRequest.getCreateUser());
            authRoleAuthorityPO.setAuthorityType(AuthConstants.AUTHORITY_TYPE_RESOURCE);
            authRoleAuthorityPO.setCreateTime(new Date());
            return authRoleAuthorityPO;
        }).collect(Collectors.toList());


        List<AuthRoleAuthorityPO> authRoleAuthorities = new ArrayList<>();
        authRoleAuthorities.addAll(roleResources);
        authRoleAuthorities.addAll(roleMenus);
        authRoleAuthorities.addAll(defaultResource);
        // 为角色添加 资源和菜单
        int roleAuthorityAdd = authRoleAuthorityDao.insertBatch(authRoleAuthorities);
        return roleAuthorityAdd > 0 && roleAdd > 0;
    }

    /**
     * 根据角色id 获取角色信息
     *
     * @param roleId 角色id
     * @return AuthRoleInfoVO
     */
    @Override
    public AuthRoleInfoVO getRoleInfo(Long roleId) {
        QueryWrapper<AuthRoleAuthorityPO> queryWrapper = new QueryWrapper<>();
        queryWrapper.select(RoleAuthorityWrapperConstant.AUTHORITY_ID);
        queryWrapper.select(RoleAuthorityWrapperConstant.AUTHORITY_TYPE);
        queryWrapper.eq(RoleAuthorityWrapperConstant.ROLE_ID, roleId);
        List<AuthRoleAuthorityPO> authRoleAuthorityPOS = this.authRoleAuthorityDao.selectList(queryWrapper);
        // 角色拥有菜单id
        List<String> menuIds = authRoleAuthorityPOS.stream()
                .filter(authRoleAuthorityPO -> StringUtils.equals(authRoleAuthorityPO.getAuthorityType(), AuthConstants.AUTHORITY_TYPE_MENU))
                .map(authRoleAuthorityPO -> authRoleAuthorityPO.getAuthorityId().toString())
                .collect(Collectors.toList());

        // 角色拥有资源ids
        List<String> resourceIds = authRoleAuthorityPOS.stream()
                .filter(authRoleAuthorityPO -> StringUtils.equals(authRoleAuthorityPO.getAuthorityType(), AuthConstants.AUTHORITY_TYPE_RESOURCE))
                .map(authRoleAuthorityPO -> authRoleAuthorityPO.getAuthorityId().toString())
                .collect(Collectors.toList());
        // 查询角色信息
        AuthRolePO authRolePO = this.authRoleDao.selectById(roleId);

        // 组装VO
        return this.authRoleInfoVOConverter.doConvert(authRolePO, menuIds, resourceIds);
    }

    @Override
    @Transactional
    public boolean deleteRoleById(String operatorId, String roleId) {
        int roleDel = this.authRoleDao.deleteById(roleId);
        QueryWrapper<AuthRoleAuthorityPO> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(RoleAuthorityWrapperConstant.ROLE_ID, roleId);
        // 删除与角色资源映射关系
        this.authRoleAuthorityDao.delete(queryWrapper);
        QueryWrapper<AuthUserRolePO> queryWrapper1 = new QueryWrapper<>();
        queryWrapper1.eq(UserRoleWrapperConstant.ROLE_ID, roleId);
        // 删除角色用户映射关系
        authUserRoleDao.delete(queryWrapper1);
        return roleDel > 0 ;
    }

    @Override
    @Transactional
    public boolean updateRole(AuthRoleEditRequest authRoleEditRequest) {
        AuthRolePO authRolePO = this.authRoleDao.selectById(authRoleEditRequest.getId());
        if (Objects.isNull(authRolePO)) {
            return false;
        }
        // 修改基本信息
        authRolePO.setUpdateUser(authRoleEditRequest.getUpdateUser());
        authRolePO.setName(authRoleEditRequest.getName());
        authRolePO.setCode(authRoleEditRequest.getCode());
        authRolePO.setDescribe(authRoleEditRequest.getDescribe_());
        authRolePO.setStatus(authRoleEditRequest.getStatus());
        int authRoleEdit = this.authRoleDao.updateById(authRolePO);

        // 更新
        List<String> resRoleMenuIds = authRoleEditRequest.getMenuIds();
        if (CollectionUtils.isEmpty(resRoleMenuIds)) {
            // 删除与角色资源映射关系
            QueryWrapper<AuthRoleAuthorityPO> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq(RoleAuthorityWrapperConstant.ROLE_ID, authRoleEditRequest.getId());
            // 删除与角色资源映射关系
            int roleAuthorityDel = this.authRoleAuthorityDao.delete(queryWrapper);
            return authRoleEdit > 0 && roleAuthorityDel > 0;
        }
        // 查询角色现有 资源
        QueryWrapper<AuthRoleAuthorityPO> queryWrapper = new QueryWrapper<>();
        queryWrapper.select(RoleAuthorityWrapperConstant.AUTHORITY_ID, RoleAuthorityWrapperConstant.AUTHORITY_TYPE);
        queryWrapper.eq(RoleAuthorityWrapperConstant.ROLE_ID, authRoleEditRequest.getId());
        List<AuthRoleAuthorityPO> authRoleAuthorityPOS = this.authRoleAuthorityDao.selectList(queryWrapper);
        // 角色拥有菜单id
        List<String> menuIds = authRoleAuthorityPOS.stream()
                .filter(authRoleAuthorityPO -> StringUtils.equals(authRoleAuthorityPO.getAuthorityType(), AuthConstants.AUTHORITY_TYPE_MENU))
                .map(authRoleAuthorityPO -> authRoleAuthorityPO.getAuthorityId().toString())
                .collect(Collectors.toList());
        // 过滤出新增的菜单
        List<AuthRoleAuthorityPO> newRoleMenuIds = resRoleMenuIds.stream()
                .filter(s -> !menuIds.contains(s)).map(menuId -> {
                    AuthRoleAuthorityPO authRoleAuthorityPO = new AuthRoleAuthorityPO();
                    authRoleAuthorityPO.setId(ObjectIdUtils.getInstance().nextId());
                    authRoleAuthorityPO.setRoleId(authRolePO.getId());
                    authRoleAuthorityPO.setAuthorityId(Long.parseLong(menuId));
                    authRoleAuthorityPO.setAuthorityType(AuthConstants.AUTHORITY_TYPE_MENU);
                    authRoleAuthorityPO.setCreateUser(authRoleEditRequest.getUpdateUser());
                    authRoleAuthorityPO.setCreateTime(new Date());
                    return authRoleAuthorityPO;
                })
                .collect(Collectors.toList());
        // 新增加角色拥有的菜单
        if (!CollectionUtils.isEmpty(newRoleMenuIds)) {
            this.authRoleAuthorityDao.insertBatch(newRoleMenuIds);
        }
        // 过滤出删除的菜单id
        List<String> delRoleMenuIds = menuIds.stream()
                .filter(s -> !resRoleMenuIds.contains(s))
                .collect(Collectors.toList());
        // 删除角色菜单
        if (!CollectionUtils.isEmpty(delRoleMenuIds)) {
            QueryWrapper<AuthRoleAuthorityPO> delWrapper = new QueryWrapper<>();
            delWrapper.eq(RoleAuthorityWrapperConstant.ROLE_ID, authRoleEditRequest.getId());
            delWrapper.in(RoleAuthorityWrapperConstant.AUTHORITY_ID, delRoleMenuIds);
            this.authRoleAuthorityDao.delete(delWrapper);
        }


        List<String> resResourceIds = authRoleEditRequest.getResourceIds();
        // 角色拥有资源ids
        List<String> resourceIds = authRoleAuthorityPOS.stream()
                .filter(authRoleAuthorityPO -> StringUtils.equals(authRoleAuthorityPO.getAuthorityType(), AuthConstants.AUTHORITY_TYPE_RESOURCE))
                .map(authRoleAuthorityPO -> authRoleAuthorityPO.getAuthorityId().toString())
                .collect(Collectors.toList());
        // 更新角色拥有的资源
        // 过滤出新增的资源
        List<AuthRoleAuthorityPO> newResourceIds = resResourceIds.stream().filter(s -> !resourceIds.contains(s))
                .map(authorityId -> {
                    AuthRoleAuthorityPO authRoleAuthorityPO = new AuthRoleAuthorityPO();
                    authRoleAuthorityPO.setId(ObjectIdUtils.getInstance().nextId());
                    authRoleAuthorityPO.setRoleId(authRolePO.getId());
                    authRoleAuthorityPO.setAuthorityId(Long.parseLong(authorityId));
                    authRoleAuthorityPO.setAuthorityType(AuthConstants.AUTHORITY_TYPE_RESOURCE);
                    authRoleAuthorityPO.setCreateUser(authRoleEditRequest.getUpdateUser());
                    authRoleAuthorityPO.setCreateTime(new Date());
                    return authRoleAuthorityPO;
                })
                .collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(newResourceIds)) {
            this.authRoleAuthorityDao.insertBatch(newResourceIds);
        }
        // 过滤出删除的资源
        List<String> delRoleResourceIds = resourceIds.stream()
                .filter(s -> !resResourceIds.contains(s))
                .collect(Collectors.toList());
        // 删除角色资源
        if (!CollectionUtils.isEmpty(delRoleResourceIds)) {
            QueryWrapper<AuthRoleAuthorityPO> delWrapper = new QueryWrapper<>();
            delWrapper.eq(RoleAuthorityWrapperConstant.ROLE_ID, authRoleEditRequest.getId());
            delWrapper.in(RoleAuthorityWrapperConstant.AUTHORITY_ID, delRoleResourceIds);
            this.authRoleAuthorityDao.delete(delWrapper);
        }

        return authRoleEdit > 0;
    }

    @Override
    public Page<AuthRolePO> getRoleList(AuthRoleQueryRequest authRoleQueryRequest) {

        Page<AuthRolePO> page = new Page<>();
        page.setCurrent(authRoleQueryRequest.getPage().getPageNum());
        page.setSize(authRoleQueryRequest.getPage().getPageSize());
        QueryWrapper<AuthRolePO> queryWrapper = new QueryWrapper<>();
        queryWrapper.select(RoleWrapperConstant.ID, RoleWrapperConstant.CODE, RoleWrapperConstant.NAME, RoleWrapperConstant.STATUS, RoleWrapperConstant.DESCRIBE, RoleWrapperConstant.TYPE);
        if (StringUtils.isNotEmpty(authRoleQueryRequest.getRoleCode())) {
            queryWrapper.like(RoleWrapperConstant.NAME, authRoleQueryRequest.getRoleCode());
        }
        return this.authRoleDao.selectPage(page, queryWrapper);

    }
}

